<template>
  <div class="design">
    <div class="toolbar">
      <el-button link class="toolbar-btn" :icon="renderIcon('DocumentAdd')" @click="showNewModuleDialog">{{locale.studio.design.createNewModule}}
      </el-button>
      <el-button link class="toolbar-btn" :icon="renderIcon('InfoFilled')" :title="locale.studio.design.moduleInfo"
                 :disabled="designer.spaceCurrentIndex<0"
                 @click="()=>{moduleInfoDialogShow=true}"/>
      <el-divider direction="vertical"/>
      <el-button link class="toolbar-btn" @click="save" :icon="renderIcon('fa Save')">
        {{ locale.studio.design.save }}
      </el-button>
      <el-divider direction="vertical"/>
      <el-button link class="toolbar-btn" :disabled="undoDisabled" title="" @click="undoHistory"
                 :icon="renderIcon('RefreshLeft')">
        {{ locale.studio.design.undo }}
      </el-button>
      <el-button link class="toolbar-btn" :disabled="redoDisabled" title="" @click="redoHistory"
                 :icon="renderIcon('RefreshRight')">
        {{ locale.studio.design.redo }}
      </el-button>
      <el-button link class="toolbar-btn" title="" @click="revertFile"
                 :icon="renderIcon('Failed')">
        {{ locale.studio.design.revert }}
      </el-button>
      <el-divider direction="vertical"/>
      <el-button link class="toolbar-btn" :disabled="clipCopyDisabled" title="" @click="clipCopy"
                 :icon="renderIcon('DocumentCopy')">
        {{ locale.studio.design.copy }}
      </el-button>
      <el-button link class="toolbar-btn" :disabled="pasteDisabled" title="" @click="clipPaste"
                 :icon="renderIcon('List')">
        {{ locale.studio.design.paste }}
      </el-button>
      <el-divider direction="vertical"/>
      <el-button link class="toolbar-btn" @click="clearFormWidget" :icon="renderIcon('Files')">{{ locale.studio.design.resetLayout }}
      </el-button>
      <PreviewModule :designer="designer" :vcxt="vcxt" @before-review="beforeReview"/>
    </div>
    <div class="sub-toolbar">
      <div class="editor-fixed" style="cursor: pointer;padding: 0 5px;" @click.stop="showAllEvents($event)">
        <el-icon>
          <Memo/>
        </el-icon>
        <el-drawer v-model="eventMenuIsOpen" :title="locale.studio.design.allEvents" direction="ltr" :size="600">
          <el-table :data="eventMenus" style="height:100%" @row-click="handleEventMap">
            <el-table-column prop="displayName" label="组件" :width="400"/>
            <el-table-column prop="label" label="属性名" :width="200"/>
          </el-table>
        </el-drawer>
      </div>
      <el-select v-model="bindKey" :placeholder="locale.studio.design.eventOrProperty" placement="bottom"
                 fit-input-width
                 style="min-width: 300px;" :disabled="_bindKeyDisabled"
                 @change="_bindKeyClick">
        <el-option-group key="event" label="事件">
          <el-option v-for="item in componentDesc.events" :label="item.name" :value="item.name">
            <span :style="{float: 'left', fontWeight: tryGetEvent(item.name)}">{{ item.name }}</span>
            <span style="float: right; color: var(--el-text-color-secondary); font-size: 13px;">{{ item.desc }}</span>
          </el-option>
        </el-option-group>
        <el-option-group key="bind" label="属性">`
          <el-option v-for="item in componentDesc.bind" :label="item.name" :value="item.name">
            <span :style="{float: 'left', fontWeight: tryGetBind(item.name)}">{{ item.name }}</span>
            <span style="float: right; color: var(--el-text-color-secondary); font-size: 13px;">{{ item.desc }}</span>
          </el-option>
        </el-option-group>
      </el-select>

      <div class="toolbar-icon"><span class="icon iconfont icon-equal"></span></div>

      <div class="design-code-wrap">
        <div :class="bindKey?'':'editor-disabled'"></div>
        <JsSrcEditor v-model="bindValue" language="javascript" :style="{height:(_isExpressExpand?310:31)+'px'}"
                     ref="bindValueEditor"
                     :class="_isExpressExpand?'expand':''"
                     express-mode
                     @editor-focus="_bindValueFocus"
                     @editor-blur="_bindValueBlur"
        />
      </div>

    </div>
    <div class="content">
      <div class="tree-menu">
        <div :class="(currentTab === '模块'?'selected':'')" @click="selectTab('模块')" :title="locale.studio.design.modules">
          <span class="icon iconfont icon-mokuai1"></span>
        </div>
        <div :class="(currentTab === '工具箱'?'selected':'')" @click="selectTab('工具箱')" :title="locale.studio.design.toolbox"><span
            class="icon iconfont icon-gongjuxiang"></span></div>
        <div :class="(currentTab === '大纲'?'selected':'')" @click="selectTab('大纲')" :title="locale.studio.design.outline"><span
            class="icon iconfont icon-kechengdagang"></span></div>
      </div>
      <div class="content-split">
        <split :class="[this._hideLeft ? 'hideLeft1':'','default-theme','split-wrap']" @onDrag="dragEnd"
               :first-area-default-size="300" :last-area-default-size="300">
          <split-area :min-size='5' :size='15' class="left">
            <component
                :is="leftCmp"
                @hide-this="hideLeft"
                @openModule="openModule"
                :showNewModule="$refs.moduleDialog"
                :ref="setLeftCmp"
            />
          </split-area>
          <split-area :size="70" class="center">
            <div v-if="designer.spaceCurrentIndex<0">
              <el-empty description="未打开模块"></el-empty>
            </div>
            <template v-else>
              <el-row class="content-tabs">
                <template v-for="(id,idx) in designer.spaceIdList">
                  <el-button :class="idx===designer.spaceCurrentIndex? 'selected':''"
                             @click="designer.switchSpace(idx).finally()">{{
                      designer.spaceInfo[id].label
                    }}
                    <el-icon @click.stop="designer.closeSpace(idx).finally()">
                      <Close/>
                    </el-icon>
                  </el-button>
                </template>
              </el-row>
              <DesignerPaint :designer="designer" :vcxt="vcxt"/>
              <div class="toolbar-bottom">
                <el-button-group class="btn-left">
                  <el-button :type="layoutType === 'PC' ?'primary':'default'" @click="changeLayoutType('PC')">PC
                  </el-button>
                  <el-button :type="layoutType === 'PDA' ?'primary':'default'" @click="changeLayoutType('PDA')">PDA
                  </el-button>
                  <el-button :type="layoutType === 'RF' ?'primary':'default'" @click="changeLayoutType('RF')">RF
                  </el-button>
                </el-button-group>

                <div class="btns-add-dialog">
                  <template v-for="dlg in dialogs">
                    <el-button v-if="dlg.type==='main'" :type="dlg.isSelected?'primary':'default'"
                               @click="selectDialogId(dlg.id)">{{ dlg.title }}
                    </el-button>
                    <el-dropdown split-button trigger="click"
                                 v-else
                                 :type="dlg.isSelected?'primary':'default'"
                                 @click="selectDialogId(dlg.id)"

                    >{{ dlg.title }}
                      <template #dropdown>
                        <el-dropdown-menu>
                          <el-dropdown-item @click="removeDialogById(dlg.id)">删除</el-dropdown-item>
                        </el-dropdown-menu>
                      </template>
                    </el-dropdown>
                  </template>
                  <el-button class="add" link @click="createDialog" :icon="renderIcon('Plus')"/>
                </div>

                <ModuleCode class="btn-right" :designer="designer" :vcxt="vcxt" @before-review="beforeReview"/>
              </div>
            </template>
          </split-area>
          <split-area :size="15" :min-size='5'>
            <component :is="currentPropComponent"
                       :vjson="currentVJson"
                       :designer="designer"
                       :vcxt="vcxt"
            />
          </split-area>
        </split>
      </div>
    </div>
    <CreateModule ref="moduleDialog" @submitNewModule="submitNewModule"/>

    <el-dialog title="添加对话框" v-model="createDialogShow" :append-to-body="true" width="300px"
               @opened="createDialogOpened">
      <el-form :model="createDialogForm" ref="vForm" :rules="[]" label-position="right" label-width="80px"
               size="default" @submit.native.prevent>
        <el-form-item label="引用名" prop="reference">
          <el-input ref="createDialogTitle" v-model="createDialogForm.reference" type="text"/>
        </el-form-item>
        <el-form-item label="标题" prop="title">
          <el-input v-model="createDialogForm.title" type="text" clearable/>
        </el-form-item>
        <el-form-item label="类型" prop="xtype">
          <el-select v-model="createDialogForm.xtype">
            <el-option label="对话框" value="dialog"/>
            <el-option label="抽屉" value="drawer"/>
          </el-select>
        </el-form-item>
        <el-form-item label="宽度" prop="width">
          <el-input v-model="createDialogForm.width" clearable/>
        </el-form-item>
      </el-form>
      <template #footer>
        <div>
          <el-button type="primary" @click="createDialogCommit">确认</el-button>
        </div>
      </template>
    </el-dialog>

    <el-dialog title="模块详情" v-model="moduleInfoDialogShow" :append-to-body="true">
      <el-descriptions size="large" direction="horizontal" :column="1">
        <el-descriptions-item label="名称">{{ getModuleInfo().label }}</el-descriptions-item>
        <el-descriptions-item label="绝对路径">{{ getModuleInfo().module.designJs.absolutePath }}</el-descriptions-item>
        <el-descriptions-item label="修改时间">{{
            formatTimestamp(getModuleInfo().module.designJs.lastModified)
          }}
        </el-descriptions-item>
        <el-descriptions-item label="Vue文件">{{ getModuleInfo().module.vue.absolutePath }}</el-descriptions-item>
      </el-descriptions>
    </el-dialog>
  </div>
</template>
<script>
import _ from "lodash"
import {h, markRaw, nextTick, reactive, toRaw, defineAsyncComponent} from 'vue'
import {Close, Memo, Place} from '@element-plus/icons-vue'
import {ElEmpty} from 'element-plus'
import VJsonContext from "../../runtime/VJsonContext"
import {renderIcon} from '../../components/web/webutils'
import Split from '../../components/web/split/split.vue'
import SplitArea from '../../components/web/split/split-area.vue'
import ResetLayout from './ResetLayout.vue'
import eventBus from "../event-bus"
import PreviewModule from "./PreviewModule.vue"
import CreateModule from './CreateModule.vue'
import Designer from './Designer'
import DesignerPaint from "./DesignerPaint.vue";
import DesignFile from './DesignFile.vue'
import DesignToolbox from './DesignToolbox.vue'
import DesignOutline from './DesignOutline.vue'
import ModuleCode from './ModuleCode.vue'
import YvI18nMixin from "@/components/YvI18nMixin";

const JsSrcEditor = defineAsyncComponent(() => import('./DesignMonacoEditor.vue'))

window.onload = function () {
  // 两个窗口之间通信消息
  // 关联 MultiPage.vue:openStudioModule
  // 关联 TreeMenuLayout.vue:showStudio
  window.addEventListener('message', function (event) {
    const path = event.data?.path
    if (!path) {
      return
    }

    // path格式: /src/pages/rule/lot/RuleLot.vue
    const currentYvStudioDesign = window['current_yv_studio_design']
    if (!currentYvStudioDesign) {
      return
    }
    system.invokeStudio("DesignModuleFile@getPcModuleByVue", {path: path}).then(({data}) => {
      if (data[0]) {
        system.invokeStudio("DesignModuleFile@getModuleFileContent", data[0]).then(({data: content}) => {
          currentYvStudioDesign.openModule(content, data[0])
        })
      }
    })
  });
}

export default {
  components: {
    ModuleCode,
    JsSrcEditor,
    DesignerPaint,
    DesignFile,
    DesignToolbox,
    DesignOutline,
    PreviewModule,
    CreateModule,
    Split,
    SplitArea, Close, Place, Memo
  },
  mixins: [YvI18nMixin],
  data() {
    const raw = new Designer(this)
    const designer = reactive(raw)
    window['designer'] = designer

    const raw2 = new VJsonContext()
    const vcxt = reactive(raw2)

    vcxt.designer = designer
    vcxt.designerConfig = this.designerConfig

    window.getDesigner = () => {
      return toRaw(designer)
    }
    window.getVcxt = () => {
      return toRaw(vcxt)
    }

    return {
      ignore: {},
      designer: designer,
      vcxt: vcxt,

      /**
       * leftBar 相关属性
       */
      currentTab: "模块",
      leftCmp: markRaw(() => {
        // <el-empty desc='1212' />
        return h(ElEmpty, {description: '请选择'})
      }),
      currentPropComponent: markRaw(() => {
        // <el-empty desc='1212' />
        return h(ElEmpty, {description: '未选择组件'})
      }),
      currentVJson: undefined,

      /**
       * bind 相关属性
       */
      bindKey: '',
      bindValue: '',
      _bindKeyDisabled: true,
      _bindValueChangeAllow: false,
      _hideLeft: false,
      _isExpressExpand: false,

      eventMenus: [],
      eventMenuIsOpen: false,

      moduleInfoDialogShow: false,
      createDialogShow: false,
      createDialogForm: {
        xtype: 'dialog',
        title: '',
        width: '400px',
      },
      componentDesc: {
        bind: [],
        events: []
      },
    }
  },
  mounted() {
    this.designer.loadSpace()
    window['current_yv_studio_design'] = this
  },
  activated() {
    const me = this;
    let running = false
    this.clearInt = setInterval(() => {
      if (running || me.__revertFile2) return;
      const vuePath = this.getModuleInfo().module.vue.absolutePath;
      const vuePathLastModified = this.getModuleInfo().module.vue.lastModified;
      const designJsPath = this.getModuleInfo().module.designJs.absolutePath;
      const designJsPathLastModified = this.getModuleInfo().module.designJs.lastModified;
      if (this.ignore[designJsPath]) return;
      running = true;
      system.invokeStudio("DesignModuleFile@checkLastModified", {
        vuePath,
        vuePathLastModified,
        designJsPath,
        designJsPathLastModified,
      }).then(res => {
        if (res.data === true) {
          me.revertFile2();
          me.__revertFile2 = true;
        }
        // console.log("@@@", res);
      }).finally(() => {
        running = false;
      })
    }, 3_000_000);
  },
  deactivated() {
    if (this.clearInt) {
      clearInterval(this.clearInt);
    }
  },
  watch: {
    '_isExpressExpand': {
      handler(newVal) {
      }
    },
    'currentTab': {
      immediate: true,
      handler(newVal) {
        this.leftCmpProps = {designer: this.designer, vcxt: this.vcxt}
        switch (newVal) {
          case '模块':
            this.leftCmp = markRaw(() => {
              return h(DesignFile, {designer: this.designer, vcxt: this.vcxt})
            })
            break;
          case '工具箱':
            this.leftCmp = markRaw(() => {
              return h(DesignToolbox, {designer: this.designer, vcxt: this.vcxt})
            })
            break;
          case '大纲':
            this.leftCmp = markRaw(() => {
              return h(DesignOutline, {designer: this.designer, vcxt: this.vcxt})
            })
            break;
        }
      }
    },
    'designer.selectedWidget': {
      handler(newVal) {
        this.currentPropComponent = getDesignPropCmp(newVal, designer)
        this.currentVJson = newVal

        if (newVal) {
          this._bindKeyDisabled = false
          if (!newVal.xtype && typeof newVal.layout === "string") {
            // 布局属性池
            this.componentDesc = {
              bind: [],
              events: this.isRf ? [
                {name: 'onCreated', desc: '创建时触发'},
                {name: 'onMounted', desc: '渲染后触发'},
                {name: 'onUnmounted', desc: '销毁后触发'},
                {name: 'onGoBack', desc: '返回到页面时候触发'},
              ] : [
                {name: 'onCreated', desc: '创建时触发'},
                {name: 'onMounted', desc: '渲染后触发'},
                {name: 'onUnmounted', desc: '销毁后触发'},
              ]
            }

          } else {
            // 组件属性池
            const desc = getComponentDesc(newVal.xtype)
            if (!desc) {
              // 没有找到组件
              this.componentDesc = {
                bind: [],
                events: []
              }

            } else {
              this.componentDesc = {
                bind: desc.props.filter(i => i.bindable === true),
                events: desc.events
              }
            }
          }

        } else {
          this._bindKeyDisabled = true
        }

        this.bindKey = ''
      }
    },
    'bindKey': {
      handler(bindKey) {
        if (!bindKey) {
          this._bindValueChangeAllow = false
          this.bindValue = ''
          nextTick(() => {
            this._bindValueChangeAllow = true
          })
          return
        }

        let eventContent = ''

        const bindTarget = _.find(this.componentDesc.bind, i => i.name === bindKey)
        if (bindTarget != null) {
          if (this.designer.selectedWidget.bind) {
            eventContent = this.designer.selectedWidget.bind[bindKey] ?? ''
          }
        }

        const eventTarget = _.find(this.componentDesc.events, i => i.name === bindKey)
        if (eventTarget != null) {
          if (this.designer.selectedWidget.listeners) {
            eventContent = this.designer.selectedWidget.listeners[bindKey] ?? ''
          }
        }

        this._bindValueChangeAllow = false
        this.bindValue = eventContent
        nextTick(() => {
          this._bindValueChangeAllow = true
        })
      }
    },
    'bindValue': {
      handler(bindValue) {
        if (!this._bindValueChangeAllow) {
          return
        }

        // this.saveCodeRaise(this, bindValue)
        const componentDesc = toRaw(this.componentDesc)
        const selectedWidget = this.designer.selectedWidget
        const bindKey = this.bindKey
        this.saveCodeRaise(this, componentDesc, selectedWidget, bindKey, bindValue)
      }
    }
  },
  computed: {
    dialogs() {
      const selectedDialogId = this.designer.selectedDialogId
      const result = [
        {title: '主界面', type: 'main', isSelected: !selectedDialogId}
      ]
      _.forEach(this.designer.vjson.dialogs, (dialog, idx) => {
        result.push({
          title: dialog.title ?? '对话框' + idx,
          id: dialog.id,
          isSelected: selectedDialogId === dialog.id,
          type: 'dialog'
        })
      })

      return result
    },

    undoDisabled() {
      return !this.designer.undoEnabled()
    },

    redoDisabled() {
      return !this.designer.redoEnabled()
    },

    clipCopyDisabled() {
      return this.designer.mulSelect.length <= 0
    },

    pasteDisabled() {
      return !this.designer.clipData || !this.designer.selectedWidget
    },

    layoutType() {
      return this.designer.getLayoutType()
    },

    isRf() {
      return this.designer.vjson.layout === "MobileDefaultLayout";
    },
  },
  methods: {
    renderIcon,
    createDialogOpened() {
      this.$refs.createDialogTitle.focus()
    },
    createDialog() {
      this.createDialogShow = true
      const seq = (_.size(this.designer.vjson.dialogs ?? []) + 1)
      this.createDialogForm = {
        xtype: 'dialog',
        title: '对话框' + seq,
        reference: 'dialog' + seq,
        width: '400px',
        isShow: false
      }
    },
    createDialogCommit() {
      const id = _.uniqueId('dialog')
      const newVJson = {
        id: id,
      }

      if (!this.designer.vjson.dialogs) {
        this.designer.vjson.dialogs = []
      }
      if (this.createDialogForm.xtype === 'dialog') {
        _.assign(newVJson, {
          width: this.createDialogForm.width,
          ...DialogDefault
        })

      } else if (this.createDialogForm.xtype === 'drawer') {
        _.assign(newVJson, {
          size: this.createDialogForm.width,
          ...DrawerDefault
        })
      }

      _.assign(newVJson, {
        xtype: this.createDialogForm.xtype,
        title: this.createDialogForm.title,
        reference: this.createDialogForm.reference,
        items: []
      })

      this.designer.vjson.dialogs.push(newVJson)
      this.designer.emitHistoryChange()

      this.createDialogShow = false
      this.$nextTick(() => {
        this.designer.selectedDialogId = id
      })
    },
    selectDialogId(dialogId) {
      this.designer.selectedDialogId = dialogId
      this.designer.clearSelected()
      this.$nextTick(() => {
        this.designer.setSelected(this.designer.vjson)
        this.designer.saveCurrentHistoryStep()
      })
    },
    removeDialogById(dialogId) {
      this.designer.selectedDialogId = null
      _.remove(this.designer.vjson.dialogs, i => i.id === dialogId)
      this.$nextTick(() => {
        this.designer.saveCurrentHistoryStep()
      })
    },
    showCodeWindow() {
      const id = this.designer.spaceIdList[this.designer.spaceCurrentIndex]
      const newWindow = window.open('/code.html?id=' + id, id, 'status=yes,toolbar=no,scrollbars=1,titlebar=no,width=800,height=600,top=200,left=200');
      if (newWindow.focus) {
        newWindow.focus()
      }

      window['designerFuncChangeCallback'] = (id, funcObj, funcPropName, newValue) => {
        const nowId = this.designer.spaceIdList[this.designer.spaceCurrentIndex]

        if (id === nowId) {
          // 被通知，当前页面的内容被重读
          this.designer.loadFormContentFromStorage().finally()
        }
      }
    },
    revertFile() {
      const id = this.designer.spaceIdList[this.designer.spaceCurrentIndex]
      const info = this.designer.spaceInfo[id]
      if (info?.module) {
        const {path, name} = info.module
        system.confirm('文件将重新从服务端拉取，真的要这样？ 路径:' + path + '/' + name).then(() => {
          system.invokeStudio("DesignModuleFile@getModuleFileContent", info.module).then(({data: content}) => {
            if (content?.designJs) {
              this.designer.loadFormFile(content.designJs)
              system.msg('还原文件成功')
              this.getModuleInfo().module.designJs.lastModified = content.designJsPathLastModified;
              this.getModuleInfo().module.vue.lastModified = content.vuePathLastModified;
              this.designer.saveSpace().finally();
            } else {
              system.showErrorDialog('无法获取文件内容:' + id)
            }
          })
        })
      } else {
        system.showErrorDialog('找不到文件信息:' + id)
      }
    },
    revertFile2() {
      const id = this.designer.spaceIdList[this.designer.spaceCurrentIndex]
      const info = this.designer.spaceInfo[id]
      if (info?.module) {
        const {path, name} = info.module
        system.confirm('文件发生变化，需要重新从服务端拉取？ 路径:' + path + '/' + name).then(() => {
          system.invokeStudio("DesignModuleFile@getModuleFileContent", info.module).then(({data: content}) => {
            if (content?.designJs) {
              this.designer.loadFormFile(content.designJs)
              system.msg('还原文件成功')
              this.getModuleInfo().module.designJs.lastModified = content.designJsPathLastModified;
              this.getModuleInfo().module.vue.lastModified = content.vuePathLastModified;
              this.designer.saveSpace().finally();
            } else {
              system.showErrorDialog('无法获取文件内容:' + id)
            }
          })
        }).catch(() => {
          // console.log("@#￥@@#");
          this.ignore[info.module.designJs.absolutePath] = true;
        }).finally(() => {
          this.__revertFile2 = false;
        })
      } else {
        system.showErrorDialog('找不到文件信息:' + id)
      }
    },
    showAllEvents(evt) {
      const eventMap = this.designer.buildEventMap()

      this.eventMenus = eventMap
      this.eventMenuIsOpen = true
    },
    handleEventMap(row, column, evt) {
      const {cmpId, propName} = row
      if (!cmpId) {
        system.msg("can't select cmpId:" + cmpId)
        return
      }
      if (cmpId === 'ROOT') {
        this.eventMenuIsOpen = false
        this.designer.setSelected(this.designer.vjson)
        nextTick(() => {
          this.bindKey = propName
          nextTick(() => {
            this.$refs.bindValueEditor.focus()
          })
        })
        return
      }
      this.designer.selectById(cmpId)
      nextTick(() => {
        if (this.designer.selectedId === cmpId) {
          this.eventMenuIsOpen = false
          this.bindKey = propName
          nextTick(() => {
            this.$refs.bindValueEditor.focus()
          })

        } else {
          system.msg("can't select " + cmpId)
        }
      })
    },
    _bindKeyClick() {
      this.$nextTick(() => {
        _.defer(() => {
          this.$refs.bindValueEditor.focus()
        })
      })
    },
    formatTimestamp(timestamp) {
      if (typeof timestamp === 'string') {
        timestamp = parseInt(timestamp)
      }
      const date = new Date(timestamp)
      const Y = date.getFullYear()
      const M = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
      const D = date.getDate()
      return `${Y}-${M}-${D} ${date.toTimeString().substr(0, 8)}`
    },
    getModuleInfo() {
      // console.log("@@ this.designer.spaceIdList")
      const id = this.designer.spaceIdList[this.designer.spaceCurrentIndex]
      if (!id) {
        return {}
      }

      return this.designer.spaceInfo[id] ?? {}
    },
    dragEnd() {
      eventBus.$emit('bem-refresh', {sender: this, source: 'split-dragEnd'})
    },
    clipCopy() {
      this.designer.clipCopy()
    },
    clipPaste() {
      this.designer.tryPaste()
    },
    _bindValueFocus() {
      if (this.bindKey) {
        this._isExpressExpand = true
      }
    },
    _bindValueBlur() {
      this._isExpressExpand = false
    },
    setLeftCmp(ref) {
      switch (this.currentTab) {
        case '模块':
          this.left_1 = ref
          break;
        case '工具箱':
          this.left_2 = ref
          break;
        case '收藏':
          this.left_3 = ref
          break;
        case '大纲':
          this.left_4 = ref
          break;
        case 'API':
          this.left_5 = ref
          break;
      }
    },
    beforeReview(review) {
      if (this.$refs._design_code) {
        try {
          this.$refs._design_code.tryLoadFile()

        } catch (e) {
          system.showErrorDialog('编译错误, 请修正后再预览', e)
          debugger
          review.cancel = true
        }
      }
    },

    hideLeft() {
      this._hideLeft = true
      // this.currentTab = ''
    },

    save() {
      const module = this.designer.spaceIdList[this.designer.spaceCurrentIndex]
      if (!module) return;
      const designJs = this.designer.exportFile()
      system.invokeStudio("DesignModuleFile@saveFile", {
        absolutePath: `${module}.design.js`,
        content: designJs,
      }).then((res) => {
        system.msg('保存成功')
        this.getModuleInfo().module.designJs.lastModified = res.data.lastModified;
        this.designer.saveSpace().finally();
        // console.log("###", res)
      }).catch(() => system.msg('保存失败，请重试！'))
    },

    undoHistory() {
      this.designer.undoHistoryStep(this)
    },

    redoHistory() {
      this.designer.redoHistoryStep(this)
    },

    changeLayoutType(newType) {
      this.designer.changeLayoutType(newType)
    },

    clearFormWidget() {
      system.showDialog(ResetLayout, {
        layout: this.designer.vjson.layout,
        title: '选择要重置的布局'

      }).then(res => {
        this.designer.clearSelected()
        const tt = getLayoutEmptyTemplate(res.layout)
        if (tt) {
          this.designer.loadFormFile(tt)
        }
      })
    },
    selectTab(name) {
      this._hideLeft = false
      this.currentTab = name
    },
    tryGetEvent(name) {
      if (!this.designer.selectedWidget?.listeners) {
        return ''
      }
      return (this.designer.selectedWidget.listeners[name] ? 'bold' : '')
    },
    tryGetBind(name) {
      if (!this.designer.selectedWidget?.bind) {
        return ''
      }
      return (this.designer.selectedWidget.bind[name] ? 'bold' : '')
    },

    saveCodeRaise: _.debounce((me, componentDesc, selectedWidget, bindKey, bindValue) => {

      me.saveCode(componentDesc, selectedWidget, bindKey, bindValue)

    }, 200),

    saveCode(componentDesc, selectedWidget, bindKey, bindValue) {
      if (!bindKey) {
        system.showErrorDialog('没有指定事件或属性名')
        return
      }

      const bindTarget = _.find(componentDesc.bind, i => i.name === bindKey)
      if (bindTarget != null) {
        if (!selectedWidget.bind) {
          selectedWidget.bind = {}
        }

        if (bindValue) {
          // console.log('write bind[' + bindKey + ']', selectedWidget, bindValue)
          selectedWidget.bind[bindKey] = bindValue
        } else {
          delete selectedWidget.bind[bindKey]
        }
      }

      const eventTarget = _.find(componentDesc.events, i => i.name === bindKey)
      if (eventTarget != null) {
        if (!selectedWidget.listeners) {
          selectedWidget.listeners = {}
        }
        if (bindValue) {
          // console.log('write listeners[' + bindKey + ']', selectedWidget, bindValue)
          selectedWidget.listeners[bindKey] = bindValue
        } else {
          delete selectedWidget.listeners[bindKey]
        }
      }
      // system.msg('保存成功')
    },
    openModule(content, module) {
      this.designer.createSpace(module.absolutePath + '/' + module.name, module, content.designJs).finally()
    },
    showNewModuleDialog() {
      this.$refs.moduleDialog.show()
    },
    submitNewModule(newModuleForm) {
      system.invokeStudio("DesignModuleFile@createModule", newModuleForm)
          .then(() => {
            this.left_1?.reloadPcModule();
            this.$refs.moduleDialog.close();
          })
    },
  }
}
</script>

<style lang="less">
* {
  box-sizing: border-box;
}

.newModuleForm .el-form-item {
  width: 100%;
}

.design {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;

  .toolbar {
    height: 38px;
    flex-grow: 0;
    display: flex;
    flex-direction: row;
    padding: 0 5px;
    background: var(--sub-header-color);

    .toolbar-btn {
      padding: 0 10px;
      line-height: 38px;
      cursor: pointer;
      font-size: 14px;
      font-weight: normal;

      &:not(.is-disabled):focus, &:not(.is-disabled):hover {
        background: #c5c5c5;
        border-radius: 0;
        color: #000
      }
    }

    .el-divider {
      height: auto;
    }
  }

  .sub-toolbar {
    height: 38px;
    line-height: 38px;
    flex-grow: 0;
    display: flex;
    flex-direction: row;
    border-top: 1px solid #ccc;
    background: var(--sub-header-color);
    position: relative;
    z-index: 2;

    .el-select {
      margin: 3px 0 0 3px;

      .el-input__wrapper {
        box-shadow: none;
        border: 1px solid #ccc;
        border-radius: 0;
      }

      .el-input.is-focus .el-input__wrapper {
        box-shadow: none !important;
      }

      .el-input__inner {
        height: 28px !important;
      }
    }

    .toolbar-icon {
      text-align: center;
      padding: 0 10px;
    }

    .btn {
      text-align: center;
      padding: 0 5px;
      cursor: pointer;

      span {
        font-size: 26px;
      }
    }

    .design-code-wrap {
      width: 100%;
      padding-top: 3px;
      position: relative;
      /*z-index: 3;*/

      .editor-disabled {
        position: absolute;
        width: 100%;
        height: 31px;
        left: 0;
        top: 3px;
        background-color: rgba(0, 0, 0, .1);
        z-index: 3;
      }

      & > .codeEditBox {
        border: 1px solid #ccc;
        position: relative;
        z-index: 2;

        &.expand {
          box-shadow: 3px 3px 3px rgb(0 0 0 / 50%);
        }

        .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main {
          flex-direction: row;
          font-size: 14px;

          .suggest-icon {
            font-size: 14px;
          }
        }
      }
    }

    & > input {
      flex: 1;
      margin: 3px 5px 3px 0;
      border: 1px solid #ccc;
      padding: 0 10px
    }
  }

  .content {
    flex: 1;
    border-top: 1px solid #ccc;
    display: flex;
    flex-direction: row;
    overflow: hidden;
    position: relative;
    z-index: 1;

    .tree-menu {
      width: 42px;
      min-width: 42px;
      flex-grow: 0;
      display: flex;
      flex-direction: column;
      border-right: 1px solid #ccc;
      background: var(--sub-header-color);

      & > div {
        cursor: pointer;
        text-align: center;
        padding: 15px 0;
        box-sizing: border-box;

        &.selected {
          background: #fff;
          position: relative;
          transition: all .3s linear;

          &:before {
            content: '';
            position: absolute;
            width: 3px;
            height: 20px;
            background: var(--main-color);
            top: 14px;
            left: 2px;
            border-radius: 5px;
            transition: background 1s linear;
          }
        }
      }
    }

    .content-split {
      flex-grow: 1;

      .split-wrap {
        height: 100%;
        width: 100%;
        background: var(--sub-header-color);

        &.hideLeft1 > .left {
          display: none;
        }

        &.hideLeft1 div:nth-child(2) {
          display: none;
        }

        .left {
        }

        .center {
          display: flex;
          flex-direction: column;

          .form-widget-container {
            background: #919191;
            position: relative;
            overflow: hidden;

            .yv-designer.full-height-width {
              height: auto
            }

            & > .yv-design-mode.full-height-width {
              height: 100%;
              overflow-y: auto;
              overflow-x: hidden;
            }
          }

          .content-tabs {
            /*border-left: 1px solid #dcdbdc;*/

            button {
              background: none;
              border-radius: 0;
              border: none;
              border-bottom: 2px solid transparent;

              .el-icon {
                margin-left: 5px;
              }

              &:hover, &:focus {
                color: #000
              }

              &.selected {
                border-bottom: 2px solid var(--main-color);
                font-weight: bold;
                color: #000
              }
            }
          }

          .toolbar-bottom {
            display: flex;
            flex-direction: row;
            justify-content: space-between;
            padding: 0 10px;

            .btn-left {
              margin: 5px 0;
            }

            .btn-right {
              margin: 5px 0;
            }

            .btns-add-dialog {
              position: relative;

              &:before {
                content: '';
                width: 1px;
                height: 21px;
                background: #ccc;
                position: absolute;
                left: -10px;
                top: 5px
              }

              &:after {
                content: '';
                width: 1px;
                height: 21px;
                background: #ccc;
                position: absolute;
                right: 0;
                top: 5px
              }

              .el-button--default {
                background: none;
                border-top: 0
              }

              .el-button--primary {
                background: #fff;
                color: var(--el-color-primary);
                border-top: 0;
                border-bottom: 3px solid #919191;
                //box-shadow: inset 0px 0px 20px 0px var(--el-color-primary)
              }

              .add {
                padding: 0 10px;
                margin-left: 0;
              }

              .el-button-group {
                .el-button--default:first-child {
                  border-right: 0;

                  &:hover {
                    border-color: var(--el-border-color)
                  }
                }

                .el-dropdown__caret-button {
                  &:hover {
                    border-color: var(--el-border-color)
                  }

                  &.el-button--default:hover {
                    color: var(--el-color-primary);
                  }

                  &.el-button--primary:hover {
                    border-right-color: var(--el-color-primary);
                    border-bottom-color: #919191;
                  }
                }

                .el-dropdown__caret-button::before {
                  display: none
                }
              }
            }
          }
        }

        .right {
        }
      }

      & > .splitpanes {
        & > .splitpanes__splitter {
          /*background: #dcdbdc;*/
        }

        &.default-theme > .splitpanes__splitter:before, &.default-theme > .splitpanes__splitter:after {
          background: #000;
        }
      }
    }
  }
}
</style>